﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using TechNewLogic.GraphIT;
using TechNewLogic.GraphIT.Hv;
using TechNewLogic.GraphIT.Hv.Legend;
using TechNewLogic.GraphIT.Hv.Vertical;
using TechNewLogic.GraphIT.Printing;

namespace TestHost
{
	/// <summary>
	/// Interaction logic for DemoControl.xaml
	/// </summary>
	public partial class DemoControl : IDisposable
	{
		private readonly IResetDemo _resetDemo;
		private static readonly Random Random;

		static DemoControl()
		{
			Random = new Random((int)DateTime.Now.Ticks);
		}

		public DemoControl(IResetDemo resetDemo)
		{
			_resetDemo = resetDemo;
			InitializeComponent();

			//GuardReleaseVersion();

			_onlineOfflineLegend = new OnlineOfflineLegend(
				CurveDisplay,
				"AKZ",
				"Location",
				"Aggregate",
				"Medium",
				"Physical");
			legendHolder.Content = _onlineOfflineLegend;

			ThreadPool.QueueUserWorkItem(o =>
				{
					while (true)
					{
						if (_autoReset)
							Dispatcher.Invoke(new Action(Reset));
						Thread.Sleep(2500);
					}
				});
		}

		private DateTime _startTime;
		private readonly Dictionary<TimeDoubleCurve, DataFactory> _curves
			= new Dictionary<TimeDoubleCurve, DataFactory>();

		private bool _autoReset;
		private OnlineOfflineLegend _onlineOfflineLegend;

		private TimeDoubleCurve AddCurve(
			string uom,
			double min,
			double max,
			Color color,
			RedrawTime redrawTime,
			string descriptionText1,
			string descriptionText2,
			string descriptionText3,
			string descriptionText4,
			string descriptionText5,
			CurveDrawingMode curveDrawingMode,
			IValueFormater valueFormater,
			IValueFetchStrategy valueFetchStrategy,
			AxisFormat axisFormat)
		{
			const int maxCurves = 20;
			if (_curves.Count >= maxCurves)
			{
				MessageBox.Show("You cannot add more than " + maxCurves + " curves.");
				return null;
			}

			var curve = CurveDisplay.TimeDoublePlottingSystem.AddCurve(
				uom,
				min,
				max,
				color,
				redrawTime,
				AxisMatchingMode.UomOnly,
				curveDrawingMode,
				valueFormater,
				valueFetchStrategy,
				axisFormat,
				5000);

			curve.Description.DescriptionText1 = descriptionText1;
			curve.Description.DescriptionText2 = descriptionText2;
			curve.Description.DescriptionText3 = descriptionText3;
			curve.Description.DescriptionText4 = descriptionText4;
			curve.Description.DescriptionText5 = descriptionText5;

			_curves.Add(curve, null);

			return curve;
		}

		private void GenerateData(TimeDoubleCurve curve, bool randomData)
		{
			var min = curve.DoubleAxis.ActualLowerBound;
			var max = curve.DoubleAxis.ActualUpperBound;
			var dataFactory = DataFactory.Attach(
				curve,
				_startTime,
				min,
				max,
				1,
				(max - min) / 500,
				(max - min) / 100,
				(max - min) / 2);

			// all in all: 50min
			var first = Random.Next(5, 30);
			var second = Random.Next(5, 50 - first - 5);
			second = second > 15 ? 15 : second;
			var third = 50 - first - second;
			if (!randomData)
				dataFactory.AppendSine(TimeSpan.FromMinutes(50), (_curves.Count + 1) / 15d);
			else
			{
				dataFactory.AppendPoints(TimeSpan.FromMinutes(first));
				dataFactory.AppendGap(TimeSpan.FromMinutes(second));
				dataFactory.AppendPoints(TimeSpan.FromMinutes(third));
			}

			curve.MinMinBelt = -0.9 + dataFactory.Offset;
			curve.MinBelt = -0.4 + dataFactory.Offset;
			curve.MaxBelt = 0.3 + dataFactory.Offset;
			curve.MaxMaxBelt = 0.7 + dataFactory.Offset;

			//// Belt
			//if (_curves.Count == 1)
			//{
			//    curve.MinMinBelt = -0.9 + dataFactory.Offset;
			//    curve.MinBelt = -0.4 + dataFactory.Offset;
			//    curve.MaxBelt = 0.3 + dataFactory.Offset;
			//    curve.MaxMaxBelt = 0.7 + dataFactory.Offset;
			//}

			//_curves.Add(curve, dataFactory);
		}

		private void GenerateBinaryData(TimeDoubleCurve curve)
		{
			var min = curve.DoubleAxis.ActualLowerBound;
			var max = curve.DoubleAxis.ActualUpperBound;
			var dataFactory = DataFactory.Attach(
				curve,
				_startTime,
				min,
				max,
				0.01,
				(max - min) / 500,
				(max - min) / 100,
				(max - min) / 2);

			// all in all: 50min
			dataFactory.AppendBinary(TimeSpan.FromMinutes(50));

			//curve.MinMinBelt = -0.9 + dataFactory.Offset;
			//curve.MinBelt = -0.4 + dataFactory.Offset;
			//curve.MaxBelt = 0.3 + dataFactory.Offset;
			//curve.MaxMaxBelt = 0.7 + dataFactory.Offset;

			//_curves.Add(curve, dataFactory);
		}

		public string ApplicationTitle
		{
			get { return "CLR Runtime:   " + Environment.Version; }
		}

		private void Print_Click(object sender, RoutedEventArgs e)
		{
		}

		private void PrintPreview_Click(object sender, RoutedEventArgs e)
		{
		}

		private void ToggleOnline_Click(object sender, RoutedEventArgs e)
		{
			if (CurveDisplay.TimeDoublePlottingSystem.IsOnline)
				CurveDisplay.TimeDoublePlottingSystem.DisableOnlineMode();
			else
				CurveDisplay.TimeDoublePlottingSystem.EnableOnlineMode(DateTime.Now);
		}

		private void Reset_Click(object sender, RoutedEventArgs e)
		{
			_autoReset = !_autoReset;
			Reset();
		}

		private void Reset()
		{
			//_resetDemo.Reset();

			var tmpCurves = new TimeDoubleCurve[_curves.Keys.Count];
			_curves.Keys.CopyTo(tmpCurves, 0);

			// ungroup all axes before removing curves
			var groups = new List<DoubleAxesGroup>();
			groups.AddRange(CurveDisplay.TimeDoublePlottingSystem.AxesGroups);
			foreach (var doubleAxesGroup in groups)
			{
				CurveDisplay.TimeDoublePlottingSystem.UngroupAxesGroup(doubleAxesGroup);
			}

			// remove curves from plotting system
			foreach (var curveToRemove in tmpCurves)
			{
				CurveDisplay.TimeDoublePlottingSystem.RemoveCurve(curveToRemove);
			}

			_curves.Clear();

			_startTime = new DateTime(2012, 3, 25, 0, 0, 0);
			//_startTime = DateTime.UtcNow;
			CurveDisplay.TimeDoublePlottingSystem.TimeAxis.SetBounds(
				//new DateTime(2012, 3, 25, 0, 0, 0),
				//new DateTime(2012, 3, 25, 5, 0, 0));
				_startTime,
				_startTime.AddHours(5));

			//_refreshCurveDataTimer = new DispatcherTimer();
			//_refreshCurveDataTimer.Interval = TimeSpan.FromSeconds(3);
			//_refreshCurveDataTimer.Tick += refreshCurveDataTimer_Tick;
			//_refreshCurveDataTimer.Start();

			var curve = AddCurve("%", 0, 100, Colors.Green, RedrawTime.Ms500, "R2033", "House 20", "BHKW",
				"Istwert", "Power Calc.", CurveDrawingMode.SimpleLine(), new FloatingCommaValueFormater(),
				new InterpolationValueFetchStrategy(), AxisFormat.Double);
			GenerateData(curve, false);
			curve = AddCurve("m³/h", 0, 10, Colors.Yellow, RedrawTime.Ms500, "U2031", "House 20", "BHKW", "Gas",
				"Quantity", CurveDrawingMode.SimpleLine(), new FloatingCommaValueFormater(),
				new InterpolationValueFetchStrategy(), AxisFormat.Double);
			GenerateData(curve, false);
			curve = AddCurve("kW", 0, 100, Colors.Red, RedrawTime.Ms500, "U2002", "House 20", "BHKW", "Heater",
				"Heating Actual", CurveDrawingMode.SimpleLine(), new FloatingCommaValueFormater(),
				new InterpolationValueFetchStrategy(), AxisFormat.Double);
			GenerateData(curve, false);
			curve = AddCurve("°C", -20, 20, Colors.Blue, RedrawTime.Ms500, "T2051", "House 20", "Outer Temp.",
				"Curr. Value", "Temperature", CurveDrawingMode.FilledRectangleAuto(),
				new FloatingCommaValueFormater(), new InterpolationValueFetchStrategy(), AxisFormat.Double);
			GenerateData(curve, false);
			curve = AddCurve("°C", 20, 60, Colors.Orange, RedrawTime.Ms500, "T2051", "House 20", "Outer Temp.",
				"Curr. Value", "Temperature", CurveDrawingMode.FilledRectangleHighest(),
				new FloatingCommaValueFormater(), new InterpolationValueFetchStrategy(), AxisFormat.Double);
			GenerateData(curve, false);
			curve = AddCurve("°C", -0.2, 1.2, Colors.PaleTurquoise, RedrawTime.Ms500, "T2051", "House 20",
				"Outer Temp.", "Curr. Value", "Temperature", CurveDrawingMode.FilledRectangleHighest(),
				new BinaryValueFormater(), new SimpleValueFetchStrategy(), AxisFormat.Double);
			GenerateBinaryData(curve);
			CurveDisplay.TimeDoublePlottingSystem.AxesGroups.First(
				it => it.DoubleAxes.Contains(curve.DoubleAxis)).IgnoreCanvasMovementOrZoom = true;
		}

		#region Implementation of IDisposable

		public void Dispose()
		{
			_onlineOfflineLegend.Dispose();
			CurveDisplay.Dispose();
		}

		#endregion

		#region Custom Controls

		private void AddCustomControl_Click(object sender, RoutedEventArgs e)
		{
		}

		private void AddCustomControl1_Click(object sender, RoutedEventArgs e)
		{
		}

		private void RemoveCustomControl_Click(object sender, RoutedEventArgs e)
		{
		}

		private void AddCustomControl2_Click(object sender, RoutedEventArgs e)
		{
		}

		private void RemoveCustomControl2_Click(object sender, RoutedEventArgs e)
		{
		}

		#endregion

		private void RemoveCurve_Click(object sender, RoutedEventArgs e)
		{
			if (_curves.Count == 0)
				return;
			var curve = _curves.First();
			CurveDisplay.TimeDoublePlottingSystem.RemoveCurve(curve.Key);
			_curves.Remove(curve.Key);
		}

		private void AppendData_Click(object sender, RoutedEventArgs e)
		{
			if (_curves.Count == 0)
				return;
			var curve = _curves.First();
			curve.Value.AppendPoints(TimeSpan.FromSeconds(10));
		}

		private void PrependData_Click(object sender, RoutedEventArgs e)
		{
			throw new NotImplementedException();
			//if (_curves.Count == 0)
			//    return;
			//var curve = _curves.First();
			//curve.Value.PrependPoints(TimeSpan.FromSeconds(10));
		}

		private void ToggleVisibility_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.Curves.OfType<TimeDoubleCurve>().ToList().ForEach(it => it.IsVisible = !it.IsVisible);
		}

		private void ShowAxes_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.TimeDoublePlottingSystem.SetScalesVisibility(true, true, true);
		}

		private void HideAxes_Click(object sender, RoutedEventArgs e)
		{
			CurveDisplay.TimeDoublePlottingSystem.SetScalesVisibility(false, false, false);
		}

		private void Dispose_Click(object sender, RoutedEventArgs e)
		{
			_resetDemo.Reset();
		}

		private void ChangeColor_Click(object sender, RoutedEventArgs e)
		{
			var curve = _curves.Keys.FirstOrDefault();
			if (curve == null)
				return;
			curve.Stroke = curve.Stroke == Colors.Yellow ? Colors.Blue : Colors.Yellow;
		}
	}
}
